/**
 * 对原生 Array 的扩展，摆脱 lodash 的依赖从你我做起
 */
export class ArrayExtension extends Array {

    /**
     * 高级版 forEach，遇到返回值为 true 的情况，立即终止循环
     * 
     * @example
     * [0,1,2,3].foreach(i => {
     *     if (i === 2) return true;
     *     console.log(i);
     * }); // 输出: 0 1
     */
    public foreach<T>(callback: (item: T, index?: number, array?: T[]) => boolean | void) {
        for (let i = 0; i < this.length; ++i) {
            if (callback(this[i], i, this)) {
                break;
            }
        }
    }

    /**
     * 对元素求和，可以使用 `iteratee` 进行处理
     * 
     * @example
     * [1,2,3].sum();           // 6
     * [1,2,3].sum(i => i * i); // 14
     */
    public sum<T>(iteratee?: (item: T) => number) {
        let result = 0;
        this.forEach(i => result += iteratee ? iteratee(i) : +i);
        return result;
    }

    /**
     * 通过规则函数把数组通过规则分类
     * 
     * @param rule 规则函数
     * @example
     * const objs = [
     *   {id: 1, type: 0},
     *   {id: 2, type: 1},
     *   {id: 3, type: 0}
     * ];
     * const grouped = objs.groupBy(i => i.type);   // {0: [{id: 1, type: 0}, {id: 3, type: 0}], 1: [{id: 2, type: 1}]}
     */
    public groupBy<T>(rule: (item: T) => unknown): Record<string, T[]> {
        const obj = {};
        this.forEach(item => {
            const key = String(rule(item));
            if (!obj[key]) {
                obj[key] = [];
            }
            obj[key].push(item);
        });
        return obj;
    }

    /**
     * nodejs 环境的 polyfill，参考 core-js 的实现
     * @see https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/es.array.at.js
     */
    public at<T>(index: number): T {
        const k = index >= 0 ? index : this.length + index;
        return (k < 0 || k >= this.length) ? undefined : this[k];
    }
}